/**
 @file ctc_asw_mirror.c

 @date 2020-08-03

 @version v1.0

---file comments----
*/
#include "ctc_asw_common.h"
#include "ctc_port.h"
#include "ctc_mirror.h"
#include "asw/include/drv_api.h"

#define CTC_ASW_MIRROR_INVALID_PORT 0x3F
#define __mirror_api__
/**
@brief This function is to set mirror enable on port
*/
int32
ctc_asw_mirror_set_port_en(uint8 lchip, uint32 gport, ctc_direction_t dir, bool enable, uint8 session_id)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    IngressPort_m igs_port;
    EgressPort_m egs_port;

    CTC_MAX_GPORT_CHECK(gport);
    CTC_MAX_VALUE_CHECK(dir, CTC_BOTH_DIRECTION);

    sal_memset(&igs_port, 0, sizeof(IngressPort_m));
    sal_memset(&egs_port, 0, sizeof(EgressPort_m));

    CTC_API_LOCK(lchip);
    if ((CTC_INGRESS == dir) || (CTC_BOTH_DIRECTION == dir))
    {
        cmd = DRV_IOR(IngressPort_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, gport, cmd, &igs_port);
        SetIngressPort(V, mirrorEn_f, &igs_port, (enable?1:0));
        cmd = DRV_IOW(IngressPort_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, gport, cmd, &igs_port);
    }
    if ((CTC_EGRESS == dir) || (CTC_BOTH_DIRECTION == dir))
    {
        cmd = DRV_IOR(EgressPort_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, gport, cmd, &egs_port);
        SetEgressPort(V, mirrorEn_f, &egs_port, (enable?1:0));
        cmd = DRV_IOW(EgressPort_t, DRV_ENTRY_FLAG);
        ret = ret?ret:DRV_IOCTL(lchip, gport, cmd, &egs_port);
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
@brief This function is to set local mirror destination port
*/
int32
ctc_asw_mirror_add_session(uint8 lchip, ctc_mirror_dest_t* mirror)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    GlobalCtrl_m global_ctrl;
    EgPortThdCtrl_m eg_port_thd_ctrl;

    CTC_MAX_GPORT_CHECK(mirror->dest_gport);

    sal_memset(&global_ctrl, 0, sizeof(GlobalCtrl_m));

    CTC_API_LOCK(lchip);
    cmd = DRV_IOR(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &global_ctrl);
    SetGlobalCtrl(V, mirrorDport_f, &global_ctrl, mirror->dest_gport);
    cmd = DRV_IOW(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &global_ctrl);

    cmd = DRV_IOR(EgPortThdCtrl_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, mirror->dest_gport, cmd, &eg_port_thd_ctrl);
    SetEgPortThdCtrl(V, shareIndex_f, &eg_port_thd_ctrl, CTC_ASW_QOS_PORT_CELL_MIN_PROFILE_MIRROR);
    SetEgPortThdCtrl(V, minIndex_f, &eg_port_thd_ctrl, CTC_ASW_QOS_PORT_CELL_MIN_PROFILE_MIRROR);
    cmd = DRV_IOW(EgPortThdCtrl_t, DRV_ENTRY_FLAG);
    ret = ret ? ret : DRV_IOCTL(lchip, mirror->dest_gport, cmd, &eg_port_thd_ctrl);

    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
@brief This function is to remove mirror destination port
*/
int32
ctc_asw_mirror_remove_session(uint8 lchip, ctc_mirror_dest_t* mirror)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    uint32 value = 0;
    GlobalCtrl_m global_ctrl;
    EgPortThdCtrl_m eg_port_thd_ctrl;

    CTC_MAX_GPORT_CHECK(mirror->dest_gport);

    sal_memset(&global_ctrl, 0, sizeof(GlobalCtrl_m));
    
    CTC_API_LOCK(lchip);

    cmd = DRV_IOR(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &global_ctrl);
    value = GetGlobalCtrl(V, mirrorDport_f, &global_ctrl);
    SetGlobalCtrl(V, mirrorDport_f, &global_ctrl, CTC_ASW_MIRROR_INVALID_PORT);
    cmd = DRV_IOW(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &global_ctrl);

    if(CTC_ASW_MIRROR_INVALID_PORT != value)
    {
        cmd = DRV_IOR(EgPortThdCtrl_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip, value, cmd, &eg_port_thd_ctrl);
        SetEgPortThdCtrl(V, shareIndex_f, &eg_port_thd_ctrl, 0);
        SetEgPortThdCtrl(V, minIndex_f, &eg_port_thd_ctrl, 0);
        cmd = DRV_IOW(EgPortThdCtrl_t, DRV_ENTRY_FLAG);
        ret = ret ? ret : DRV_IOCTL(lchip, value, cmd, &eg_port_thd_ctrl);
    }

    CTC_API_UNLOCK(lchip);

    return ret;
}

int32
ctc_asw_mirror_get_port_info(uint8 lchip, uint32 gport, ctc_direction_t dir, bool* enable, uint8* session_id)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    IngressPort_m igs_port;
    EgressPort_m egs_port;

    CTC_MAX_GPORT_CHECK(gport);
    CTC_MAX_VALUE_CHECK(dir, CTC_EGRESS);
    CTC_PTR_VALID_CHECK(enable);

    sal_memset(&igs_port, 0, sizeof(IngressPort_m));
    sal_memset(&egs_port, 0, sizeof(EgressPort_m));

    CTC_API_LOCK(lchip);
    if (CTC_INGRESS == dir)
    {
        cmd = DRV_IOR(IngressPort_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, gport, cmd, &igs_port);
        *enable = GetIngressPort(V, mirrorEn_f, &igs_port);
    }
    if (CTC_EGRESS == dir)
    {
        cmd = DRV_IOR(EgressPort_t, DRV_ENTRY_FLAG);
        ret = DRV_IOCTL(lchip, gport, cmd, &egs_port);
        *enable = GetEgressPort(V, mirrorEn_f, &egs_port);
    }
    CTC_API_UNLOCK(lchip);

    return ret;
}

/**
 @brief This function is to initialize the mirror module
*/
int32
ctc_asw_mirror_init(uint8 lchip, void* mirror_global_cfg)
{
    int32 ret = CTC_E_NONE;
    uint32 cmd = 0;
    GlobalCtrl_m global_ctrl;

    sal_memset(&global_ctrl, 0, sizeof(GlobalCtrl_m));
    cmd = DRV_IOR(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = DRV_IOCTL(lchip, 0, cmd, &global_ctrl);
    SetGlobalCtrl(V, mirrorDport_f, &global_ctrl, CTC_ASW_MIRROR_INVALID_PORT);
    cmd = DRV_IOW(GlobalCtrl_t, DRV_ENTRY_FLAG);
    ret = ret?ret:DRV_IOCTL(lchip, 0, cmd, &global_ctrl);

    return CTC_E_NONE;
}

int32
ctc_asw_mirror_deinit(uint8 lchip)
{
    return CTC_E_NONE;
}
